package com.zackeus.sipservice;

import android.os.Parcel;
import android.os.Parcelable;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.zackeus.common.utils.ObjectUtils;
import com.zackeus.common.utils.StringUtils;
import com.zackeus.sipservice.constant.AuthScheme;
import com.zackeus.sipservice.constant.TransportType;

import org.pjsip.pjsua2.AuthCredInfo;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * sip 账户
 * @name: SipAccountData
 * @author: zz
 * @date: 2022/9/15
 */
public class SipAccountData implements Parcelable {

    private String username;
    private String password;
    private String host;
    private String realm;
    private long port;

    /* 传输类型 */
    @TransportType.Unit
    private String transportType = TransportType.UDP;

    /* 认证方案 */
    @AuthScheme.Unit
    private  String authScheme = AuthScheme.DIGEST;

    /* 附加URI参数 以分号为前缀 如: ;my-param=X;another-param=Hi％20there */
    private Map<String, String> contactUriParams = new HashMap<>();
    /* 注册间隔 单位: s */
    private int regExpirationTimeout = 300;
    /* 呼叫ID */
    private String callId = "";

    public SipAccountData(@NonNull String username, @NonNull String password, @NonNull String host) {
        this(username, password, host, null, 5060);
    }

    public SipAccountData(@NonNull String username, @NonNull String password, @NonNull String host,
                          @Nullable String realm, long port) {
        this.username = username;
        this.password = password;
        this.host = host;
        this.realm = realm;
        this.port = port;
    }

    public String getUsername() {
        return username;
    }

    public SipAccountData setUsername(String username) {
        this.username = username;
        return this;
    }

    public String getPassword() {
        return password;
    }

    public SipAccountData setPassword(String password) {
        this.password = password;
        return this;
    }

    public String getRealm() {
        if (StringUtils.isBlank(this.realm)) {
            return this.host;
        }
        return realm;
    }

    public SipAccountData setRealm(String realm) {
        this.realm = realm;
        return this;
    }

    public String getHost() {
        return host;
    }

    public SipAccountData setHost(String host) {
        this.host = host;
        return this;
    }

    public long getPort() {
        return port;
    }

    public SipAccountData setPort(long port) {
        this.port = port;
        return this;
    }

    @TransportType.Unit
    public String getTransportType() {
        return transportType;
    }

    public SipAccountData setTransportType(@TransportType.Unit String transportType) {
        this.transportType = transportType;
        return this;
    }

    @AuthScheme.Unit
    public String getAuthScheme() {
        return authScheme;
    }

    public SipAccountData setAuthScheme(@AuthScheme.Unit String authScheme) {
        this.authScheme = authScheme;
        return this;
    }

    public SipAccountData setContactUriParam(Map<String, String> params){
        this.contactUriParams = params;
        return this;
    }

    public String getContactUriParam(){
        if (ObjectUtils.isEmpty(this.contactUriParams))
            return "";

        StringBuilder contactUriParam = new StringBuilder();
        for (Map.Entry<String, String> entry : contactUriParams.entrySet()) {
            contactUriParam.append(String.format(";%s=%s", entry.getKey(), entry.getValue()));
        }
        return contactUriParam.toString();
    }

    public SipAccountData setRegExpirationTimeout(int regExpirationTimeout){
        this.regExpirationTimeout = regExpirationTimeout;
        return this;
    }

    public int getRegExpirationTimeout(){
        return this.regExpirationTimeout;
    }

    public String getCallId() {
        return callId;
    }

    public SipAccountData setCallId(String callId) {
        this.callId = callId;
        return this;
    }

    /**
     * 凭证资料
     * @return
     */
    AuthCredInfo getAuthCredInfo() {
        return new AuthCredInfo(authScheme, getRealm(), username, 0, password);
    }

    public String getIdUri() {
        if (StringUtils.isBlank(realm))
            return "sip:" + username + "@" + host;

        if ("*".equals(realm))
            return "sip:" + username;

        return "sip:" + username + "@" + realm;
    }

    String getProxyUri() {
        return "sip:" + host + ":" + port;
    }

    String getRegistrarUri() {
        return "sip:" + host + ":" + port;
    }

    public static final Parcelable.Creator<SipAccountData> CREATOR =
            new Parcelable.Creator<SipAccountData>() {
                @Override
                public SipAccountData createFromParcel(final Parcel in) {
                    return new SipAccountData(in);
                }

                @Override
                public SipAccountData[] newArray(final int size) {
                    return new SipAccountData[size];
                }
            };

    @Override
    public void writeToParcel(Parcel parcel, int arg1) {
        parcel.writeString(username);
        parcel.writeString(password);
        parcel.writeString(realm);
        parcel.writeString(host);
        parcel.writeLong(port);
        parcel.writeString(transportType);
        parcel.writeString(authScheme);
        parcel.writeMap(contactUriParams);
        parcel.writeInt(regExpirationTimeout);
        parcel.writeString(callId);
    }

    private SipAccountData(Parcel in) {
        username = in.readString();
        password = in.readString();
        realm = in.readString();
        host = in.readString();
        port = in.readLong();
        transportType = in.readString();
        authScheme = in.readString();
        in.readMap(contactUriParams, String.class.getClassLoader());
        regExpirationTimeout = in.readInt();
        callId = in.readString();
    }

    @Override
    public int describeContents() {
        return 0;
    }

    SipAccountData copy() {
        Parcel parcel = Parcel.obtain();
        this.writeToParcel(parcel, 0);
        parcel.setDataPosition(0);
        SipAccountData temp = SipAccountData.CREATOR.createFromParcel(parcel);
        parcel.recycle();
        return temp;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        SipAccountData that = (SipAccountData) o;

        if (!Objects.equals(username, that.username)) return false;
        if (!Objects.equals(password, that.password)) return false;
        if (!Objects.equals(realm, that.realm)) return false;
        if (!Objects.equals(host, that.host)) return false;
        if (port != that.port) return false;
        if (!Objects.equals(transportType, that.transportType)) return false;
        if (!Objects.equals(authScheme, that.authScheme)) return false;
        if (!Objects.equals(contactUriParams, that.contactUriParams)) return false;
        if (regExpirationTimeout != that.regExpirationTimeout) return false;
        if (!Objects.equals(callId, that.callId)) return false;

        return getIdUri().equals(that.getIdUri());
    }

    @Override
    public int hashCode() {
        return Objects.hash(username, password, host, realm, port, transportType, authScheme, contactUriParams, regExpirationTimeout, callId);
    }
}
